#include "stdafx.h"
#include "MemMan.h"

//constructor/destructor//////////////////////////////////////////////////
CMemMan::CMemMan()
{
	Init();
}

CMemMan::~CMemMan()
{
	Clear();
}


//Public//////////////////////////////////////////////////////////////////
unsigned CMemMan::GetEventsCountForThread(unsigned threadIdx)
{
#ifdef _X64
	return (unsigned)(globalCollection->at(threadIdx)->size());
#else
	return globalCollection->at(threadIdx)->size();
#endif
}

unsigned CMemMan::GetThreadIndex(short item)
{
	if (threads->size() > 0)
	{
#ifdef _X64
		unsigned idx = (unsigned)(threads->size());
#else
		unsigned idx = threads->size();
#endif
		vector<short>::const_reverse_iterator iter;
		for (iter = threads->rbegin(); iter != threads->rend(); iter++)
		{
			if(*iter == item)
				return idx-1;
			idx--;
		}
	}
	threads->push_back(item);
	globalCollection->push_back(new vector<line*>);
#ifdef _X64
	return (unsigned)(threads->size() - 1);
#else
	return threads->size() - 1;
#endif
}

short CMemMan::GetTidForIndex(unsigned threadIdx)
{
	return threads->at(threadIdx);
}

unsigned CMemMan::GetThreadsCount()
{
#ifdef _X64
	return (unsigned)(threads->size());
#else
	return threads->size();
#endif
}

char* CMemMan::GetEventData(unsigned threadIdx, unsigned eventIdx, Collections colId)
{
	line *l = globalCollection->at(threadIdx)->at(eventIdx);
	switch (colId)
	{
		case CMemMan::Message:
			return l->Msg;
		case CMemMan::Time:
			return l->Time;
		case CMemMan::Service:
			return srvs->at(l->Srv);
		case CMemMan::Type:
			return (char*)(l->Type);
		default:
			return NULL;
	}

}

void CMemMan::PushLine(char* data)
{
	if (data && *data)
	{
		threadsCount++;
			if (*data == 9 || *data == 32 || *(data + 12) != 9)
				return;
			line* aLine = new line();
			memcpy(aLine->Time, data, 12);
			short tid = Hex2Short(data + 13);
			char* np = data + (tid < 0x1000 ? 17 : 18);
			aLine->Type = GetTypeFast(np); 
			np += 4;
			char* ep = np + 1;
			while(*ep != 9) ep++;
			EnterCriticalSection(&lSrvs);
				aLine->Srv = GetCharPtrColItemIndex(np, ep - np, srvs);
			LeaveCriticalSection(&lSrvs);
			aLine->Msg = PackLine(ep + 1);
			EnterCriticalSection(&lThreads);
				globalCollection->at(GetThreadIndex(tid))->push_back(aLine);
			LeaveCriticalSection(&lThreads);
		threadsCount++;
	}
}

unsigned CMemMan::PushBulk(char* data)
{
	char *sp, *ep;
	sp = data;
	ep = sp;
	while(*ep)
	{
		if(*ep == 0xA)
		{
			if(*(ep - 1) == 0xD) 
				*(ep - 1) = 0;
			*ep = 0;
			PushLine(sp);
			sp = ep + 1;
		}
		ep++;
	}
#ifdef _X64
	return (unsigned)(ep - sp);
#else
	return ep - sp;
#endif
}

//Private////////////////////////////////////////////////////////////////
void CMemMan::Init()
{
	globalCollection = new vector<vector<line*>*>();
	srvs = new vector<char*>();
	threads = new vector<short>();
	_heap = GetProcessHeap();
	_msgHeap = HeapCreate(0, 0, 0);
	for(int i = 0; i < 256; i++)
		for(int j = 0; j < 256; j++)
		{
			dictionary[i][j] = NULL;
			InitializeCriticalSection(&(locks[i][j]));
		}
	InitializeCriticalSection(&lThreads);
	InitializeCriticalSection(&lSrvs);
	SYSTEM_INFO sysinfo;
	GetSystemInfo(&sysinfo);
	threadsMax = (char)(sysinfo.dwNumberOfProcessors);
}

void CMemMan::Clear()
{
	if(globalCollection) 
	{
		for(vector<vector<line*>*>::reverse_iterator iter = globalCollection->rbegin(); iter != globalCollection->rend(); iter++)
		{
			if (*iter)
			{
				for(vector<line*>::reverse_iterator  iter2 = (*iter)->rbegin(); iter2 != (*iter)->rend(); iter2++)
				{
					if(*iter2)
					{
						HeapFree(/*_heap*/ _msgHeap, 0, (*iter2)->Msg);
						delete *iter2;
					}
				}
				delete *iter;
			}
		}
		delete globalCollection;
		globalCollection = NULL;
	}
	if(threads) 
	{
		delete threads;
		threads = NULL;
	}
	DeleteCharPtrCol(srvs);
	for(int i = 0; i < 256; i++)
		for(int j = 0; j < 256; j++)
		{
			DeleteCharPtrCol(dictionary[i][j]);
			DeleteCriticalSection(&(locks[i][j]));
		}
	DeleteCriticalSection(&lThreads);
	DeleteCriticalSection(&lSrvs);
	HeapDestroy(_msgHeap);
}

void CMemMan::DeleteCharPtrCol(vector<char*>* vect)
{
	if(vect)
	{
		for(vector<char*>::iterator iter = vect->begin(); iter != vect->end(); iter++)
			HeapFree(_heap, 0, *iter);
		delete vect;
		vect = NULL;
	}
}

char CMemMan::GetCharPtrColItemIndex(char* item, size_t sz, vector<char*>* vect)
{
	return (char)(GetCharPtrColItemIndexEx(item, sz, vect));
}

short CMemMan::GetCharPtrColItemIndexEx(char* item, size_t sz, vector<char*>* vect)
{
#ifdef _X64
	unsigned idx = (unsigned)(vect->size());
#else
	unsigned idx = vect->size();
#endif
	if (idx > 0)
	{
		vector<char*>::const_reverse_iterator iter;
		for (iter = vect->rbegin(); iter != vect->rend(); iter++)
		{
			if(strlen(*iter) == sz && !memcmp(*iter, item, sz))
				return (short)(idx-1);
			idx--;
		}
	}
	char* stg = (char*)HeapAlloc(_heap, 0, sz + 1);
	memcpy(stg, item, sz);
	stg[sz] = 0;
	vect->push_back(stg);
	return (short)(vect->size() - 1);
}

char CMemMan::GetTypeFast(char* ptr)
{
	switch (*ptr)
	{
		//All iffs here could be commented out possibly
	case 'I':
		if (ptr[1] == 'M' && ptr[2] == 'P')
			return 0;
	case 'N':
		if (ptr[1] == 'T' && ptr[2] == 'F')
			return 1;
	case 'E':
		if (ptr[1] == 'R' && ptr[2] == 'R')
			return 2;
	case 'D':
		if (ptr[1] == 'N' && ptr[2] == 'G')
			return 3;
	case 'A':
		if (ptr[1] == 'L' && ptr[2] == 'W')
			return 4;
	}
	return 255;
}

short CMemMan::Hex2Short(char* hex)
{
	short res = 0;
	while (*hex != 9)
	{
		res *= 16;
		if(*hex>=0x30 && *hex<0x3A) //0-9
			res += (*hex - 0x30);
		else if(*hex>0x40 && *hex<0x47) //A-F
			res += (*hex - 0x37);
		else if(*hex>0x60 && *hex<0x67) //a-f
			res += (*hex - 0x57);
		else
			break;
		hex++;
	}
	return res;
}

char* CMemMan::PackLine(char* src)
{
	SIZE_T len = strlen(src);
	char* msgStg = (char*)HeapAlloc(_heap, 0, len + 1);
	//BEGIN OF NEW IMPL
	char *sp, *ep, *mp, sp1;
	sp = src;		//lexem start ptr
	ep = sp;		//lexem end ptr
	mp = msgStg;	//msgStg current position ptr
	SIZE_T llen = 0;//lexem length, used below as total packed content length, too; SIZE_T used to disable x64 warnings
	while(*ep)		//== while (ep - src <= len)
	{
		while(*ep && (*ep != ' ') && (*ep != '/') && (*ep != '\\'))
			ep++;
		llen = ep - sp;
		if(llen > 5)					//there's a sense to pack lexem
		{
			sp1 = *(sp + 1);			//speed enhancement
			vector<char*>* dict = GetDictionary(*sp, sp1);
			EnterCriticalSection(&(locks[*sp][sp1]));
				short idx = GetCharPtrColItemIndexEx(sp + 2, ep - (sp + 2), dict);
			LeaveCriticalSection(&(locks[*sp][sp1]));
			*mp = 1;					//packaging symbol + collection identifiers
			*(mp + 1) = *sp;			
			*(mp + 2) = sp1;			//i.e. 2 1st letters of lexem
			*(mp + 3) = (char)(idx >> 8);//colection packed index - 4th & 5th chars
			*(mp + 4) = (char)(idx & 0xFF);
			*(mp + 5) = *ep;			//delimeter
			mp += 6;
		}
		else
		{
			memcpy(mp, sp, llen + 1);	//simply copying lexem and delimeter
			mp += (llen + 1);			//and moving msgStg pointer forwards
		}
		if(*ep)							//if not end of line
		{
			ep++;
			sp = ep;
		}
	}
	llen = mp - msgStg;					//total compressed length
	char* msgStgMsgHeap = (char*)HeapAlloc(_msgHeap, 0, llen);
	memcpy(msgStgMsgHeap, msgStg, llen);
	HeapFree(_heap, 0, msgStg);
	return msgStgMsgHeap;
	//END OF NEW IMPL
	//memcpy(msgStg, src, len);
	//msgStg[len] = 0;
	//return msgStg
}

void CMemMan::ExpandEventMessage(char* msg, char* buffer)
{
	while(true)
	{
		if(*msg == 1)
		{
			*buffer = *(msg + 1);
			*(buffer + 1) = *(msg + 2);
			char* msgContent = dictionary[*(msg + 1)][*(msg + 2)]->at((*(msg + 3)) * 256 + (*(msg + 4)));
			SIZE_T msgContentLength = strlen(msgContent); 
#pragma warning (disable: 4996)		//No security problem: log line cannot be more than 4k :)
			strcpy(buffer + 2, msgContent);
#pragma warning (default: 4996)
			msg += 5;
			buffer += (msgContentLength + 2);
		}
		else
		{
			*buffer = *msg;
			if(*msg)
			{
				buffer++;
				msg++;
			}
			else
				break;
		}
	}
}

vector<char*>* CMemMan::GetDictionary(char one, char two)
{
	if(!(dictionary[one][two]))
		dictionary[one][two] = new vector<char*>;
	return dictionary[one][two];
}